from bcat.error import InvalidArgumentError
from bcat.api.net.session import Session

from bcat.api.impl.c.service_impl import ServiceImpl
from ctypes import string_at


class SessionImpl(Session):
    def on_read(self, msg_type, msg, length, ctx):
        h = self.handler()
        if h is not None:
            h.on_read(string_at(msg, length), msg_type)

    def on_connected(self, ctx):
        if self.handler() is not None:
            self.handler().on_connected()

    def on_disconnected(self, errno, ctx):
        if self.handler() is not None:
            self.handler().on_disconnected(errno)
            if errno != 1:
                self.handler().on_error(errno)

    def __init__(self, service_impl, handler=None, **kwargs):
        super(SessionImpl, self).__init__(service_impl, handler, **kwargs)
        self.__capi = service_impl.api()

        kwargs["f_on_connected"] = self.on_connected
        kwargs["f_on_read"] = self.on_read
        kwargs["f_on_disconnected"] = self.on_disconnected
        self.__impl = self.__capi.session_create(service_impl.impl(), **kwargs)

    def __del__(self):
        self.destroy()

    def destroy(self):
        if self.__impl is not None:
            self.__capi.session_destroy(self.__impl)
            self.__impl = None

    def _check_inputs(self):
        # TODO:
        return True

    def is_connected(self):
        if self.__impl is None:
            raise InvalidArgumentError("session impl is None")
        return self.__capi.session_is_connected(self.__impl)

    def connect(self):
        if self.__impl is None and not self._check_inputs:
            raise InvalidArgumentError("session connect args error!")
        return self.__capi.session_connect(self.__impl)

    def disconnect(self):
        if self.__impl is None:
            raise InvalidArgumentError("session impl is None")

        return self.__capi.session_disconnect(self.__impl)

    def write(self, msg):
        if self.__impl is not None:
            return self.__capi.session_write(self.__impl, msg)
        else:
            raise InvalidArgumentError("session impl is None")

    def write_encrypt(self, msg):
        if self.__impl is not None:
            return self.__capi.session_write_encrypt(self.__impl, msg)
        else:
            raise InvalidArgumentError("session impl is None")

    def ip(self):
        if self.__impl is None:
            raise InvalidArgumentError("session impl is None")
        return self.__capi.session_get_ip(self.__impl)

    def port(self):
        if self.__impl is None:
            raise InvalidArgumentError("session impl is None")
        return self.__capi.session_get_port(self.__impl)

    def heartbeat_timeout(self):
        if self.__impl is None:
            raise InvalidArgumentError("session impl is None")
        return self.__capi.session_get_heartbeat_timeout(self.__impl)

    def set_heartbeat_timeout(self, second):
        if self.__impl is None:
            raise InvalidArgumentError("session impl is None")
        self.__capi.session_set_heatbeart_timeout(self.__impl, second)
